﻿#include <iostream>
#include <array>
#include <functional>

//如果我希望某个函数的入参只能是std::array该怎么做呢？
/*
 *以下是C++20前的写法
*/
template<typename T>
void fun1(T arr) {
	std::cout << __FUNCTION__ << ':' << typeid(arr).name() << std::endl;
}
/*
 * 通过std::enable_if来限定这个输入参数的类型
 * 传递该参数类型的派生类型无法通过编译
*/
template <class T>
struct is_std_array: public std::false_type {};
template <class T, size_t N>
struct is_std_array<std::array<T, N>>: public std::true_type {};
template<class T>
std::enable_if_t<is_std_array<T>::value>
foo(T arr) {
	std::cout << __FUNCTION__ << ':' << typeid(arr).name() << std::endl;
}

template <typename T, size_t N>
struct my_array: std::array<T, N>{};

/*
 * C++20 concept约束写法
*/
// 定义数组array的概念
template <typename Type>
concept array = requires(Type arr) {
	// concept array做了两个约束: 有size成员函数，能被std::get调用，
	// 凡是满足这两个约束的都认为是std::array like的概念。
	arr.size();
	std::get<0>(arr);
};
 
template<typename T>
void foo1(T arr) requires(array<T>) {
	std::cout << __FUNCTION__ << ':' << typeid(arr).name() << std::endl;
}

// 对纯类型约束
template <class T>
concept c_array = std::is_array_v<T> && std::extent_v<std::remove_cvref_t<T>> > 0;
template <typename Type>
concept c_array1 = requires(Type arr) {
	std::is_array_v<Type> == true;
}; 
// concept c_array1 = requires(Type arr) {
// 	std::is_array_v<decltype(arr)> == true;
// };
template<typename T>
void foo2(T arr) requires(c_array<T>) {
	std::cout << __FUNCTION__ << ':' << typeid(arr).name() << std::endl;
}



void test_array()
{
	fun1("123465");
	std::array<int, 5> arr0{1, 2, 3, 4, 5};
	my_array<int, 2> arr1{};
	int arr2[2];

	foo(arr0);
	// foo(arr1); //error 无法编译

	static_assert(array<std::array<int, 2>>); //ok
	foo1(arr0); //ok
	foo1(arr1); //ok 

	
}

int main(int argc, char const* argv[])
{
	test_array();
	return 0;
}
